using System;
using NUnit.Framework;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Engine;
using System.Collections;
using System.Data;

namespace NHibernate.Test.Playground
{
    public class CustomLoadingOfMultipleEntitiesSimultaneously : SimpleDynamicProperties
    {
        AbstractEntityPersister _customerPersister;
        AbstractEntityPersister _orderPersister;
        [Test]
        public void Test()
        {
            var fred = NewCustomer("Fred", "Flintstone");
            var barney = NewCustomer("Barney", "Rubble");

            var order1 = NewOrder(fred, "TRex Eggs", 5);
            var order2 = NewOrder(barney, "Pterodactyl", 1);

            var sql = CreateSql();
            var customerPropertySuffixes = GetSuffixedProperties(_customerPersister, customerSuffix);
            var orderPropertySuffixes = GetSuffixedProperties(_orderPersister, orderSuffix);

            using (var s = OpenSession())
            using (var tx = s.BeginTransaction())
            {
                try
                {
                    SaveAndEvict(s, fred, barney, order1, order2);
                    var cmd = s.Connection.CreateCommand();
                    cmd.CommandText = sql.ToString();
                    Output(cmd.CommandText);
                    var reader = cmd.ExecuteReader();
                    while (reader.Read())
                    {
                        ExtractCustomer(customerPropertySuffixes, s, reader);
                        ExtractOrder(orderPropertySuffixes, s, reader);
                    }
                }
                finally
                {
                    tx.Rollback();
                }
            }
        }
        private void ExtractCustomer(string[][] matrixSuffixedProperties, ISession sess, IDataReader reader)
        {
            var idIdx = reader.GetOrdinal(_customerPersister.GetIdentifierAliases(customerSuffix)[0]);
            Output(reader.GetGuid(idIdx));
            Customer newCustomer = new Customer();
            var ret = _customerPersister.Hydrate(reader, reader.GetGuid(0), newCustomer, _customerPersister, matrixSuffixedProperties, true, sess as ISessionImplementor);
            Output(ret);
        }
        private void ExtractOrder(string[][] matrixSuffixedProperties, ISession sess, IDataReader reader)
        {
            var idIdx = reader.GetOrdinal(_orderPersister.GetIdentifierAliases(orderSuffix)[0]);
            Output(reader.GetGuid(idIdx));
            Order newOrder = new Order(null);
            var ret = _orderPersister.Hydrate(reader, reader.GetGuid(0), newOrder, _orderPersister, matrixSuffixedProperties, true, sess as ISessionImplementor);
            Output(ret);
        }
        private static void Output(object[] array)
        {
            foreach (var val in array)
                if (val is object[])
                    foreach (var innerVal in (val as object[]))
                        Output("\t\t" + innerVal.ToString());
                else
                    Output("\t" + val.ToString());
        }
        private SqlString CreateSql()
        {
            return new SqlString("SELECT ", 
                _customerPersister.SelectFragment(customerAlias, customerSuffix), 
                ", ",
                _orderPersister.SelectFragment(orderAlias, orderSuffix),
                " FROM ", 
                _customerPersister.FromTableFragment(customerAlias),
                " LEFT OUTER JOIN ",
                _orderPersister.FromTableFragment(orderAlias),
                " ON ",                
                String.Format("{0}.{1}={2}.{3} ", customerAlias, _customerPersister.KeyColumnNames[0],orderAlias,"CustomerId"),
                _orderPersister.FromJoinFragment(orderAlias, true, true)
                );
        }
        string[][] GetSuffixedProperties(AbstractEntityPersister persister, string suffix)
        {
            var matrixSuffixedProperties = new string[persister.PropertyTypes.Length][];
            for (int i = 0; i < persister.PropertyTypes.Length; i++)
                matrixSuffixedProperties[i] = persister.GetPropertyAliases(suffix, i);
            return matrixSuffixedProperties;
        }
        void SaveAndEvict(ISession s, params object[] objects)
        {
            foreach (var obj in objects)
            {
                s.Save(obj);
                s.Flush();
                s.Evict(obj);
            }
        }
        Customer NewCustomer(string first, string last)
        {
            var customer = new Customer() { FirstName = first };
            customer.DynamicProperties.Add("LastName", last);
            return customer;
        }
        Order NewOrder(Customer customer, string name, int count)
        {
            var order = new Order(customer);
            order.DynamicProperties1["ProductName"] = name;
            order.DynamicProperties2["NumberOfOrders"] = count;
            return order;

        }
        protected override void OnSetUp()
        {
            base.OnSetUp();
            _customerPersister = (AbstractEntityPersister)sessions.GetEntityPersister(typeof(Customer).FullName);
            _orderPersister = (AbstractEntityPersister)sessions.GetEntityPersister(typeof(Order).FullName);
        }
        const string customerAlias = "cust";
        const string customerSuffix = "cs";
        const string orderAlias = "ord";
        const string orderSuffix = "os";
    }
}
